/**
 * 
 */
package wpmp.auth.service;

import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Component;

import wcommons.httputils.quickbean.RespInfo;
import wcommons.lang.UrlUtils;
import wpmp.auth.Statics;
import wpmp.auth.cache.CacheManager;
import wpmp.auth.dao.ResourceDao;
import wpmp.utils.quickbean.NeedNotLoginPermission;
import wpmp.utils.quickbean.User;
import wpmp.utils.quickbean.UserPermission;
import wpmp.utils.quickbean.UserView;

/**
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 11:48:08 AM Dec 5, 2013
 */
@Component
public class ResourceService extends BaseService {

	@Autowired
	private CacheManager cacheManager;

	@Autowired
	private ResourceDao dao;

	@Autowired
	private UserService userService;

	/**
	 * 获取无需登录的权限列表
	 * @return
	 */
	public NeedNotLoginPermission getNeedNotLoginPermission() {
		final String key = Statics.NEED_NOT_LOGIN_PERMISSION_;
		NeedNotLoginPermission result = (NeedNotLoginPermission) cacheManager.get(key);
		// 优先缓存
		if (result != null) {
			return result;
		}

		result = new NeedNotLoginPermission();

		final SqlRowSet rs = dao.listNeedNotLoginResource();
		while (rs.next()) {
			final NeedNotLoginPermission.Entry e = new NeedNotLoginPermission.Entry();
			e.setBaseUrl(rs.getString("base_url"));
			e.setActionName(rs.getString("action_name"));
			e.setOperations(rs.getString("value"));
			result.getResources().add(e);
		}

		// 保存至缓存中, 15分钟
		cacheManager.set(key, 15 * 60, result);

		return result;
	}

	/**
	 * 权限认证
	 * @param securityId
	 * @param authUrl
	 * @return 500-用户未登录 501-无效的参数 502-没有权限 200-正常
	 */
	public int check(String securityId, String authUrl) {
		final String url = new String(Base64.decodeBase64(authUrl));

		final String[] urls = UrlUtils.splitUrlParams(url);

		final Map<String, String> params = UrlUtils.getStringParamMap(urls[1]);

		// 是否不要登录可访问
		for (NeedNotLoginPermission.Entry entry : this.getNeedNotLoginPermission().getResources()) {
			if (StringUtils.equals(entry.getBaseUrl(), urls[0])) {
				final String currentAction = StringUtils.defaultIfBlank(params.get(entry.getActionName()),
						wpmp.utils.Statics.DEFAULT_ACTION);

				final String[] actions = entry.getOperations().split(",");
				for (String action : actions) {
					if (StringUtils.equals(wpmp.utils.Statics.MATCH_ALL, action) || currentAction.startsWith(action)) {
						return 200;
					}
				}
			}
		}

		// 没有登录
		if (StringUtils.isBlank(securityId)) {
			return 500;
		}

		final User user = (User) cacheManager.get(Statics.USER_ + securityId);
		// 没有登录
		if (user == null) {
			return 500;
		}
		// 管理员
		if (user.isAdmin()) {
			return 200;
		}

		final UserPermission userPermission = this.getUserPermission(securityId).getResult();
		// 不正常结果，直接返回
		if (userPermission == null) {
			return 502;
		}

		for (UserPermission.Entry entry : userPermission.getResources()) {
			if (StringUtils.equals(entry.getBaseUrl(), urls[0])) {
				final String currentAction = StringUtils.defaultIfBlank(params.get(entry.getActionName()),
						wpmp.utils.Statics.DEFAULT_ACTION);

				final String[] actions = entry.getOperations().split(",");
				for (String action : actions) {
					if (StringUtils.equals(wpmp.utils.Statics.MATCH_ALL, action) || currentAction.startsWith(action)) {
						return 200;
					}
				}
			}
		}

		return 502;
	}

	/**
	 * 获取用户权限列表
	 * @param securityId
	 * @return 500-未登录
	 */
	public RespInfo<UserPermission> getUserPermission(final String securityId) {
		final RespInfo<UserPermission> respInfo = new RespInfo<UserPermission>(200);

		User user = (User) cacheManager.get(Statics.USER_ + securityId);
		if (user == null) {
			respInfo.setCode(500);
			return respInfo;
		}

		final String key = Statics.USER_PERMISSION_ + securityId;
		UserPermission userPermission = (UserPermission) cacheManager.get(key);
		// 优先缓存
		if (userPermission != null) {
			userPermission.setUser(user);
			userPermission.setSecurityId(securityId);
			respInfo.setResult(userPermission);
			return respInfo;
		}

		userPermission = new UserPermission();

		final SqlRowSet rs;
		if (user.isAdmin()) {
			rs = dao.listAllPermission();
		}
		else {
			rs = dao.listPermissionByLoginName(user.getLoginName());
		}
		while (rs.next()) {
			final UserPermission.Entry e = new UserPermission.Entry();
			e.setBaseUrl(rs.getString("base_url"));
			e.setActionName(rs.getString("action_name"));
			e.setLevel(rs.getString("level"));
			e.setOperations(rs.getString("value"));
			userPermission.getResources().add(e);
		}

		// 保存至缓存中，默认12个小时失效
		cacheManager.set(key, 12 * 60 * 60, userPermission);

		userPermission.setUser(user);
		userPermission.setSecurityId(securityId);
		respInfo.setResult(userPermission);
		return respInfo;
	}

	/**
	 * 获取用户权限视图
	 * @param securityId
	 * @return
	 */
	public RespInfo<UserView> getUserView(final String securityId) {
		final RespInfo<UserView> respInfo = new RespInfo<UserView>(200);

		User user = (User) cacheManager.get(Statics.USER_ + securityId);
		if (user == null) {
			respInfo.setCode(500);
			return respInfo;
		}

		final String key = Statics.USER_VIEW_ + securityId;
		UserView userView = (UserView) cacheManager.get(key);
		// 优先缓存
		if (userView != null) {
			userView.setUser(user);
			userView.setSecurityId(securityId);
			respInfo.setResult(userView);
			return respInfo;
		}

		userView = new UserView();

		final UserPermission userPermission = this.getUserPermission(securityId).getResult();
		// 不正常结果，无需缓存
		if (userPermission == null) {
			return respInfo;
		}

		final SqlRowSet rs = dao.listVisiableResource();

		while (rs.next()) {
			final boolean isPublic = rs.getBoolean("is_public");
			final boolean isLeaf = rs.getBoolean("is_leaf");
			final String baseUrl = rs.getString("base_url");
			final String baseAction = rs.getString("base_action");

			if (isLeaf && !isPublic && !this.checkPermission(userPermission, baseUrl, baseAction)) {
				continue;
			}

			final String level = rs.getString("level");
			// 判断非叶子节点 是否需要显示
			if (!isLeaf && !this.checkPermission(userPermission, level) && !this.checkPermission(rs, level)) {
				continue;
			}

			final UserView.Entry e = new UserView.Entry();
			e.setId(rs.getLong("id"));
			e.setIsLeaf(isLeaf);
			e.setLevel(level);
			e.setName(rs.getString("name"));
			e.setOrderNum(rs.getInt("order_num"));
			e.setParentId(rs.getLong("parent_id"));
			if (isLeaf) {
				final String paraUrl = rs.getString("para_url");
				if (StringUtils.isBlank(paraUrl)) {
					e.setUrl(UrlUtils.spliceParams(baseUrl, rs.getString("action_name") + "=" + baseAction));
				}
				else {
					final String startsWith = rs.getString("action_name") + "=";
					final String indexOf = "&" + startsWith;
					e.setUrl(UrlUtils.spliceParams(baseUrl, paraUrl));

					if (paraUrl.startsWith(startsWith) || paraUrl.contains(indexOf)) {
						// paraUrl 里 包含 以 actionName 命名的参数，则忽略 baseAction
					}
					else {
						e.setUrl(UrlUtils.spliceParams(e.getUrl(), startsWith + baseAction));
					}
				}
			}
			userView.getResources().add(e);
		}

		// 保存至缓存中，默认12个小时失效
		cacheManager.set(key, 12 * 60 * 60, userView);

		userView.setUser(user);
		userView.setSecurityId(securityId);
		respInfo.setResult(userView);
		return respInfo;
	}

	private boolean checkPermission(SqlRowSet allVisiableResourceRs, String level) {
		final int row = allVisiableResourceRs.getRow();
		try {
			allVisiableResourceRs.beforeFirst();
			while (allVisiableResourceRs.next()) {
				if (allVisiableResourceRs.getBoolean("is_public")
						&& StringUtils.startsWith(allVisiableResourceRs.getString("level"), level)) {
					return true;
				}
			}
		}
		finally {
			if (allVisiableResourceRs.first()) {
				allVisiableResourceRs.relative(row - 1);
			}
		}
		return false;
	}

	private boolean checkPermission(UserPermission userPermission, String level) {
		for (UserPermission.Entry entry : userPermission.getResources()) {
			if (StringUtils.startsWith(entry.getLevel(), level)) {
				return true;
			}
		}
		return false;
	}

	private boolean checkPermission(UserPermission userPermission, String baseUrl, String baseAction) {
		for (UserPermission.Entry entry : userPermission.getResources()) {
			if (StringUtils.equals(entry.getBaseUrl(), baseUrl)) {
				final String[] actions = entry.getOperations().split(",");
				for (String action : actions) {
					if (StringUtils.equals(wpmp.utils.Statics.MATCH_ALL, action) || baseAction.startsWith(action)) {
						return true;
					}
				}
			}
		}
		return false;
	}
}
